/*******************************************************************************
 * Copyright (c) 2011 TXT e-solutions SpA
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * This work was performed within the IoT_at_Work Project
 * and partially funded by the European Commission's
 * 7th Framework Programme under the research area ICT-2009.1.3
 * Internet of Things and enterprise environments.
 *
 *
 * Authors:
 *     Cristoforo Seccia (TXT e-solutions SpA)
 *
 * Contributors:
 *      Domenico Rotondi (TXT e-solutions SpA)
 *******************************************************************************/
package it.txt.access.capability.demo.server.view;

import it.txt.access.capability.commons.signer.X509DocumentSigner;
import it.txt.access.capability.commons.signer.model.X509CertificateKeyValues;
import it.txt.access.capability.commons.signer.model.X509DocumentSignerInfo;
import it.txt.access.capability.demo.server.tcp.ResponseClientSupport;
import it.txt.access.capability.commons.utils.MessageUtils;
import it.txt.access.capability.demo.server.tcp.ResponseServer;
import it.txt.access.capability.demo.server.view.model.ServerResponseInfoModel;
import it.txt.access.capability.demo.server.view.model.ServiceRequestInfoModel;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.security.GeneralSecurityException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.border.SoftBevelBorder;

/**
 *
 * @author Cristoforo Seccia (TXT e-solutions SpA)
 */
public class ServerGUIController implements WindowListener, PropertyChangeListener {

    private static final Logger LOGGER = Logger.getLogger(ServerGUIController.class.getName());
    private static final Cursor DEFAULT_CURSOR = new Cursor(Cursor.DEFAULT_CURSOR);
    private static final Cursor BUSY_CURSOR = new Cursor(Cursor.WAIT_CURSOR);
    private X509CertificateKeyValues certificateKeyValues;
    private ResponseServer capabilityResponseServer;
    private static final int INVALID_PORT = -1;
    private int serverPort = INVALID_PORT;
    private ServerGUI serverGUI;

    public ServerGUIController() {
        initComponents();
    }

    private void initComponents() {
        serverGUI = new ServerGUI(this);        
    }

    public void createAndShowGui() {
        serverGUI.addWindowListener(this);
        serverGUI.setDefaultCloseOperation(ServerGUI.DO_NOTHING_ON_CLOSE);
        serverGUI.setVisible(true);
    }
    
    protected void setServerKeystoreData(X509DocumentSignerInfo signerInfo) {
        serverGUI.setCursor(BUSY_CURSOR);
        try {
            certificateKeyValues = X509DocumentSigner.getCertificateKeyValues(signerInfo);
            serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Server Keystore Path",
                    "Using Keystore: " + signerInfo.getKeystorePath()));
            serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Server Keystore Data",
                    "Using Server ID: " + signerInfo.getSignerID()));
            showInfoMessage(serverGUI, "Server Keystore Data",
                    "Using Server ID: " + signerInfo.getSignerID());
        }
        catch (GeneralSecurityException ex) {
            LOGGER.log(Level.SEVERE, ex.getMessage(), ex);
            showErrorMessage(serverGUI, "Server Keystore Data", ex.getMessage());
            serverGUI.appendLogMessage(MessageUtils.getErrorMessage("Server Keystore Data",
                    "Error while recovering Ceritificate: " + ex.getMessage()));
        }
        serverGUI.setCursor(DEFAULT_CURSOR);
    }

    protected void setServerConnectionParams(long port) {
        serverPort = (int) port;
        String title = "Server Connection Port";
        if (serverPort < 0) {
            showErrorMessage(serverGUI, title, "Server Port must be greater than zero");
            return;
        }
        if(serverPort > 0xFFFF){
            showErrorMessage(serverGUI, title, "Server Port out of range.");
            return;
        }
        String msg = "Set Server TCP Port ID: " + serverPort;
        serverGUI.appendLogMessage(MessageUtils.getInfoMessage(title, msg));
        showInfoMessage(serverGUI, title, msg);
    }

    protected boolean startServerListening() {
        if (serverPort == INVALID_PORT) {
            showErrorMessage(serverGUI, "Starting Server",
                    "Please set the Server TCP port.");
            return false;
        }
        if (certificateKeyValues == null) {
            showErrorMessage(serverGUI, "Starting Server",
                    "Please set the Server Certificate.");
            return false;
        }
        if(capabilityResponseServer != null && capabilityResponseServer.isListening()){
            showErrorMessage(serverGUI, "Starting Server",
                    "Server already started.");
            return false;
        }
        String msg = "Starting Server using TCP Port ID: " + serverPort + "...";
        serverGUI.appendLogMessage(MessageUtils.getErrorMessage("Demo Server", msg));
        //Set the server port and this, in order listen about the progress
        capabilityResponseServer = new ResponseServer(serverPort, certificateKeyValues, this);
        //Start the server listening
        new Thread(capabilityResponseServer).start();
        return true;
    }

    protected void stopServerListening() {
        if(capabilityResponseServer != null && capabilityResponseServer.isListening()){
            capabilityResponseServer.stopListening();
        }
        resetClientProgressState();
        handleServerProgressState(ResponseClientSupport.STATE_SETTINGS,
                serverGUI.getProgressRequestReadyLabel());
    }

    protected void resetClientProgressState(){
        handleServerProgressState(ResponseClientSupport.STATE_SETTINGS,
                serverGUI.getProgressServiceResponseSentLabel());
        handleServerProgressState(ResponseClientSupport.STATE_SETTINGS,
                serverGUI.getProgressServiceRequestReceivedLabel());
        handleServerProgressState(ResponseClientSupport.STATE_SETTINGS,
                serverGUI.getProgressTCPConnectionLabel());
    }

    protected static void showErrorMessage(Component parent, String title, String msg) {
        JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.ERROR_MESSAGE);
    }

    protected static void showInfoMessage(Component parent, String title, String msg) {
        JOptionPane.showMessageDialog(parent, msg, title, JOptionPane.INFORMATION_MESSAGE);
    }

    private void stopServerAndCloseApplication() {
        stopServerListening();
        serverGUI.setVisible(false);
        LOGGER.log(Level.WARNING, "Server return code (Finish: {0} - Cancel: {1} - Error: {2}): {3} ",
                new Object[]{ServerGUI.FINISH_RETURN_CODE, ServerGUI.CANCEL_RETURN_CODE,
                    ServerGUI.ERROR_RETURN_CODE, serverGUI.getReturnCode()});
        System.exit(0);
    }

    private void handleRequestReceivedInfoEvent(PropertyChangeEvent evt) {
        ServiceRequestInfoModel infoModel = (ServiceRequestInfoModel) evt.getNewValue();
        serverGUI.validateRequestDataForm(infoModel);
        serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Client Request ID: ", infoModel.getRequestID()));
        serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Client Operation: ", infoModel.getOperation()));
    }

    private void handleResponseSentInfoEvent(PropertyChangeEvent evt) {
        ServerResponseInfoModel infoModel = (ServerResponseInfoModel) evt.getNewValue();
        serverGUI.validateResponseDataForm(infoModel);
        serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Server Response ID: ", infoModel.getResponseID()));
        serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Client response Status: ", infoModel.getResponseStatus()));
    }

    private void handleReadyToAcceptStateEvent(PropertyChangeEvent evt) {
        Integer newState = (Integer) evt.getNewValue();
        JLabel progressLabel = serverGUI.getProgressRequestReadyLabel();
        handleServerProgressState(newState, progressLabel);
        serverGUI.changeStatusLabelText(evt.getPropertyName());
    }

    private void handleTCPConnectionStateEvent(PropertyChangeEvent evt) {
        Integer newState = (Integer) evt.getNewValue();
        JLabel progressLabel = serverGUI.getProgressTCPConnectionLabel();
        handleServerProgressState(newState, progressLabel);
        serverGUI.changeStatusLabelText(evt.getPropertyName());
    }

    private void handleRequestReceivedStateEvent(PropertyChangeEvent evt) {
        Integer newState = (Integer) evt.getNewValue();
        JLabel progressLabel = serverGUI.getProgressServiceRequestReceivedLabel();
        handleServerProgressState(newState, progressLabel);
        serverGUI.changeStatusLabelText(evt.getPropertyName());
    }

    private void handleResponseSentStateEvent(PropertyChangeEvent evt) {
        Integer newState = (Integer) evt.getNewValue();
        JLabel progresslabel = serverGUI.getProgressServiceResponseSentLabel();
        handleServerProgressState(newState, progresslabel);
        serverGUI.changeStatusLabelText(evt.getPropertyName());
    }

    private void handleServerProgressState(int newState, JLabel progressLabel) {
        Icon newIcon = null;
        String message = progressLabel.getText();
        switch (newState) {
            case ResponseClientSupport.STATE_OK: {
                newIcon = ServerGUI.ICON_OK;
                message += " - Ok.";
                progressLabel.setBorder(new SoftBevelBorder(SoftBevelBorder.RAISED));
                break;
            }
            case ResponseClientSupport.STATE_ERROR: {
                newIcon = ServerGUI.ICON_ERROR;
                message += " - Error.";
                progressLabel.setBorder(new SoftBevelBorder(SoftBevelBorder.RAISED));
                break;
            }
            case ResponseClientSupport.STATE_SETTINGS: {
                newIcon = ServerGUI.ICON_SETTINGS;
                message += " - reset.";
                progressLabel.setBorder(new SoftBevelBorder(SoftBevelBorder.LOWERED));
                break;
            }
        }
        progressLabel.setIcon(newIcon);
        serverGUI.appendLogMessage(MessageUtils.getInfoMessage("Demo Server", message));
    }

    public void propertyChange(PropertyChangeEvent evt) {
        LOGGER.log(Level.INFO, "Handling Event: {0} with value:{1}", new Object[]{evt.getPropertyName(), evt.getNewValue()});
        if (ResponseClientSupport.EVENT_NAME_SERVICE_REQUEST_READY.equals(evt.getPropertyName())) {
            handleReadyToAcceptStateEvent(evt);
        } else if (ResponseClientSupport.EVENT_NAME_TCP_CONNECTION.equals(evt.getPropertyName())) {
            handleTCPConnectionStateEvent(evt);
        } else if (ResponseClientSupport.EVENT_NAME_SERVICE_REQUEST_RECEIVED.equals(evt.getPropertyName())) {
            handleRequestReceivedStateEvent(evt);
        } else if (ResponseClientSupport.EVENT_NAME_SERVICE_RESPONSE_SENT.equals(evt.getPropertyName())) {
            handleResponseSentStateEvent(evt);
        } else if (ResponseClientSupport.EVENT_NAME_SERVICE_REQUEST_INFO.equals(evt.getPropertyName())) {
            handleRequestReceivedInfoEvent(evt);
        } else if (ResponseClientSupport.EVENT_NAME_SERVICE_RESPONSE_INFO.equals(evt.getPropertyName())) {
            handleResponseSentInfoEvent(evt);
        }
    }

    public void windowClosing(WindowEvent e) {
        
        if (serverGUI.getReturnCode() == ServerGUI.FINISH_RETURN_CODE) {
            stopServerAndCloseApplication();
        }
        else{
            int resp = JOptionPane.showConfirmDialog(serverGUI,
                    "Are you sure you want to close?");
            if (resp == JOptionPane.YES_OPTION) {
                stopServerAndCloseApplication();
            }
        }
    }

    public void windowOpened(WindowEvent e) {
    }

    public void windowClosed(WindowEvent e) {
    }

    public void windowIconified(WindowEvent e) {
    }

    public void windowDeiconified(WindowEvent e) {
    }

    public void windowActivated(WindowEvent e) {
    }

    public void windowDeactivated(WindowEvent e) {
    }
}
